#include <cstring>
#include <iostream>
#include <vector>

#include <uv.h>

class Main {
    struct WrittenBuffer {
        uv_write_t req;
        uv_buf_t buf;
    };

    static void OnNewConnection(uv_stream_t *server, int err)
    {
        if (err) {
            std::cerr << "OnNewConnection failed with %s" << uv_strerror(err) << std::endl;
            return;
        }

        auto client = new uv_tcp_t();
        uv_tcp_init(server->loop, client);
        if (uv_accept(server, reinterpret_cast<uv_stream_t *>(client)) == 0) {
            uv_read_start(reinterpret_cast<uv_stream_t *>(client), AllocBuffer, EchoRead);
            return;
        }

        uv_close(reinterpret_cast<uv_handle_t *>(client), DeleteClient);
    }

    static void AllocBuffer(uv_handle_t *handle, size_t suggestedSize, uv_buf_t *buf)
    {
        buf->base = new char[suggestedSize];
        buf->len = suggestedSize;
    }

    static void DeleteClient(uv_handle_t* handle)
    {
        delete reinterpret_cast<uv_tcp_t *>(handle);
    }

    static void EchoRead(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf)
    {
        if (nread > 0) {
            std::vector<uv_buf_t> bufs;
            for (ssize_t i = 0; i < nread; i += bufs.back().len + 1) {
                size_t j = i;
                while (buf->base[j] != 0 && buf->base[j] != '\n' && j < nread) {
                    j++;
                }
                bufs.push_back({&buf->base[i], j - i});
            }

            for (auto &buf : bufs) {
                printf("[%zu]: '%s'\n", buf.len, buf.base);
            }
            return;
        }

        if (nread < 0) {
            if (nread != UV_EOF) {
                std::cerr << "Read failed with " << uv_err_name(nread) << std::endl;
            }

            uv_close(reinterpret_cast<uv_handle_t *>(client), DeleteClient);
        }

        delete[] buf->base;
    }

public:
    int Run(const char *address, const int port)
    {
        uv_tcp_t server = {};
        uv_loop_t *loop = uv_default_loop();
        if (auto err = uv_tcp_init(loop, &server)) {
            std::cerr << "uv_tcp_init failed with " << uv_strerror(err) << std::endl;
            return err;
        }

        struct sockaddr_in addr;
        uv_ip4_addr(address, port, &addr);
        uv_tcp_bind(&server, reinterpret_cast<struct sockaddr *>(&addr), 0);
        if (auto err = uv_listen(reinterpret_cast<uv_stream_t *>(&server), 128, OnNewConnection)) {
            std::cerr << "uv_listen failed with " << uv_strerror(err) << std::endl;
            return err;
        }

        return uv_run(loop, UV_RUN_DEFAULT);
    }
};

int main()
{
    Main main;
    return main.Run("0.0.0.0", 7000);
}
